package wortubung.lang.fr;

import static wortubung.util.CommonUtils.*;

import wortubung.WortUbungException;
import wortubung.inflection.CONJUGATION;
import wortubung.util.ImmutableStringList;
import wortubung.util.LatinScript;

public class ConjugueurUtil {

	static final String DICTIONNAIRE1 = "Harper Collins Robert French College Dictionary 2nd Ed";
	static final String DICTIONNAIRE2 = "French-Chinese Dictionary";

	static final ImmutableStringList PRESENT_ER_INDICES = isl("e",   "es",  "e",   "ons",    "ez",    "ent");
	static final ImmutableStringList PRESENT_IR_INDICES = isl("is",  "is",  "it",  "issons", "issez", "issent");
	static final ImmutableStringList PRESENT_RE_INDICES = isl("s",   "s",   "",    "ons",    "ez",    "ent");
	static final ImmutableStringList PRESENT_SS_INDICES = isl("s",   "s",   "t",   "sons",   "sez",   "sent");
	static final ImmutableStringList PRESENT_X__INDICES = isl("x",   "x",   "t",   "ons",    "ez",    "ent");

	static final ImmutableStringList IMPARFAIT_ER_INDICES = isl("ais",    "ais",    "ait",    "ions",    "iez",    "aient");
	static final ImmutableStringList IMPARFAIT_IR_INDICES = isl("issais", "issais", "issait", "issions", "issiez", "issaient");

	static final ImmutableStringList PASSE_ER_INDICES = isl("ai",  "as",  "a",   "âmes",  "âtes",  "èrent");
	static final ImmutableStringList PASSE_IR_INDICES = isl("is",  "is",  "it",  "îmes",  "îtes",  "irent");
	static final ImmutableStringList PASSE_U__INDICES = isl("us",  "us",  "ut",  "ûmes",  "ûtes",  "urent");
	static final ImmutableStringList PASSE_IN_INDICES = isl("ins", "ins", "int", "înmes", "întes", "inrent");

	static final ImmutableStringList SUBJ_PRE_ER_INDICES = isl("e",    "es",    "e",    "ions",    "iez",    "ent");
	static final ImmutableStringList SUBJ_PRE_IR_INDICES = isl("isse", "isses", "isse", "issions", "issiez", "issent");
	static final ImmutableStringList SUBJ_PRE_A__INDICES = isl("asse", "asses", "asse", "assions", "assiez", "assent");

	static final ImmutableStringList SUBJ_IMP_ER_INDICES = isl("asse",  "asses",  "ât",  "assions",  "assiez",  "assent");
	static final ImmutableStringList SUBJ_IMP_IR_INDICES = isl("isse",  "isses",  "ît",  "issions",  "issiez",  "issent");
	static final ImmutableStringList SUBJ_IMP_U__INDICES = isl("usse",  "usses",  "ût",  "ussions",  "ussiez",  "ussent");
	static final ImmutableStringList SUBJ_IMP_IN_INDICES = isl("insse", "insses", "înt", "inssions", "inssiez", "inssent");

	static final ImmutableStringList FUTUR_INDICES       = isl("ai", "as", "a", "ons", "ez", "ont");

	static void imperatifDePresent(String[] presentConjugaison) {
		if (presentConjugaison != null) {
    		presentConjugaison[0] = presentConjugaison[2] = presentConjugaison[5] = null;
    		if (presentConjugaison[1].endsWith("es"))
    			presentConjugaison[1] = chopRight(presentConjugaison[1], 1);
		}
	}

	static String[] conjuguerER(String verbeSuffix, CONJUGATION type, boolean fairePhonetique) {
		ImmutableStringList indices = null;
		switch(type) {
		case PRESENT:        indices =   PRESENT_ER_INDICES; break;
		case IMPERFECT:      indices = IMPARFAIT_ER_INDICES; break;
		case SIMPLE_PAST:    indices =     PASSE_ER_INDICES; break;
		case SUBJ_PRESENT:   indices =  SUBJ_PRE_ER_INDICES; break;
		case SUBJ_IMPERFECT: indices =  SUBJ_IMP_ER_INDICES; break;
		default:             return null;
		}
		String racine = chopRight(verbeSuffix, 2);
		if (fairePhonetique)
			return phonetique(racine, indices, true);
		else
			return appendToRoot(racine, indices);
	}

	static String[] conjuguerIR(String verbeSuffix, CONJUGATION type) {
		ImmutableStringList indices = null;
		switch(type) {
		case PRESENT:        indices =   PRESENT_IR_INDICES; break;
		case IMPERFECT:      indices = IMPARFAIT_IR_INDICES; break;
		case SIMPLE_PAST:    indices =     PASSE_IR_INDICES; break;
		case SUBJ_PRESENT:   indices =  SUBJ_PRE_IR_INDICES; break;
		case SUBJ_IMPERFECT: indices =  SUBJ_IMP_IR_INDICES; break;
		default:             return null;
		}
		return phonetique(chopRight(verbeSuffix, 2), indices, true);
	}

	static String[] conjuguerRE(String verbeSuffix, CONJUGATION type) {
		ImmutableStringList indices = null;
		String racine = chopRight(verbeSuffix, 2);
		switch(type) {
		case PRESENT:        return conjuguerPresentSX(racine);
		case IMPERFECT:      indices = IMPARFAIT_ER_INDICES; break;
		case SIMPLE_PAST:    indices =     PASSE_IR_INDICES; break;
		case SUBJ_PRESENT:   indices =  SUBJ_PRE_ER_INDICES; break;
		case SUBJ_IMPERFECT: indices =  SUBJ_IMP_IR_INDICES; break;
		default:             return null;
		}
		return phonetique(racine, indices, false);
	}

	static String[] conjuguerPresentSX(String racine) {
		return conjuguerPresentSX(racine, false);
	}

	static String[] conjuguerPresentSX(String racine, boolean etreX) {
		return fixerSingles(phonetique(racine, etreX ? PRESENT_X__INDICES : PRESENT_RE_INDICES, false));
	}

	static String[] conjuguerPresentSX(ImmutableStringList racines) {
		return conjuguerPresentSX(racines, false);
	}

	static String[] conjuguerPresentSX(ImmutableStringList racines, boolean etreX) {
		return fixerSingles(phonetique(racines, etreX ? PRESENT_X__INDICES : PRESENT_RE_INDICES, false));
	}
	
	private static String[] fixerSingles(String[] resulte) {
		// je/tu
		String tmp = resulte[0];
		if (tmp.endsWith("rts") || tmp.endsWith("rvs") || tmp.endsWith("rms")) { // e.g., "partir", "sortir", "servir", "dormir"
			resulte[0] = chopRight(resulte[0], 3) + "rs";
			resulte[1] = chopRight(resulte[1], 3) + "rs";
		}
		else if (tmp.endsWith("nts") || tmp.endsWith("tts")) { // e.g., "mentir", "mettre", "battre"
			resulte[0] = chopRight(resulte[0], 2) + "s";
			resulte[1] = chopRight(resulte[1], 2) + "s";
		}

		// il/elle
		tmp = resulte[2];
		if (tmp.endsWith("rv") || tmp.endsWith("rm")) { // e.g., "servir", "dormir"
			resulte[2] = chopRight(tmp, 2) + "rt";
		} else if (tmp.endsWith("tt")) {
			resulte[2] = chopRight(tmp, 1); // e.g. "battre"
		} else {
			char dernier = last(tmp);
			if (dernier != 'd' && dernier != 't' && dernier != 'c')
				resulte[2] = phonetique(tmp, 't', false);
		}

		return resulte;
	}

	static String[] conjuguerU_(String verbe, CONJUGATION type) {
		ImmutableStringList indices = null;
		if (type == CONJUGATION.SIMPLE_PAST)
			indices = PASSE_U__INDICES;
		else if (type == CONJUGATION.SUBJ_IMPERFECT)
			indices = SUBJ_IMP_U__INDICES;
		else
			throw new WortUbungException("Conjugaison Type de U n'applique pas à " + type + '.');
		return phonetique(chopRight(verbe, 2), indices, verbe.endsWith("cre"));
	}

	static String[] conjuguerA_(String verbe, CONJUGATION type) {
		if (type == CONJUGATION.SUBJ_PRESENT)
			return phonetique(chopRight(verbe, 2), SUBJ_PRE_A__INDICES, false);
		throw new WortUbungException("Conjugaison Type de A n'applique pas à " + type + '.');
	}

	static String[] conjuguerIN(String verbe, CONJUGATION type) {
		if (type == CONJUGATION.SIMPLE_PAST)
			return phonetique(chopRight(verbe, 2), PASSE_IN_INDICES, false);
		if (type == CONJUGATION.SUBJ_IMPERFECT)
			return phonetique(chopRight(verbe, 2), SUBJ_IMP_IN_INDICES, false);
		throw new WortUbungException("Conjugaison Type de IN n'applique pas à " + type + '.');
	}

	// R�gles phonetiques
	
	static String phonetiqueIndicatifPourFuturEtConditionnel(String verbe) {
		// e.g. "peler", "geler", "lever", "enlever", "appeler"
		String coupePar2 = chopRight(verbe, 2);
		if (etreStresseEX(coupePar2)) {
			String dernier3 = last(verbe, 3);
			if (verbe.endsWith("ppeler") || verbe.endsWith("jeter"))
				return coupePar2 + dernier3;
			else
				return chopRight(verbe, 4) + 'è' + dernier3;
		}
		if (verbe.endsWith("oyer"))
			return chopRight(verbe, 3) + "ier";
		return verbe;
	}

	static String[] apposerIndiceFuturConditionnel(String verbeSuffix, boolean fairePhonetique, boolean etreFutur) {
		String racine;
		if ((racine = Conjugueur.defaultConjugator.getIrregularFutureRoot(verbeSuffix)) != null)
			;
		else if (verbeSuffix.endsWith("re"))
			racine = chopRight(verbeSuffix, 1);
		else if (fairePhonetique && verbeSuffix.endsWith("ayer"))
			racine = chopRight(verbeSuffix, 3) + "ier";
		else
			racine = phonetiqueIndicatifPourFuturEtConditionnel(verbeSuffix);
		return appendToRoot(racine, etreFutur ? FUTUR_INDICES : IMPARFAIT_ER_INDICES);
	}

	static String[] phonetique(String racine, ImmutableStringList suffices, boolean dernierCSonDeS) {
		String [] resulte = new String[suffices.size()];
		for (int i=0; i<suffices.size(); ++i) {
			if (suffices.get(i) != null)
				resulte[i] = phonetique(racine, suffices.get(i), dernierCSonDeS);
		}
		return resulte;
	}

	static String[] phonetique(ImmutableStringList racines, ImmutableStringList suffices, boolean dernierCSonDeS) {
		String [] resulte = new String[suffices.size()];
		for (int i=0; i<suffices.size(); ++i) {
			if (suffices.get(i) != null)
				resulte[i] = phonetique(racines.get(i), suffices.get(i), dernierCSonDeS);
		}
		return resulte;
	}

	static String phonetique(String racine, String suffix, boolean dernierCSonDeS) {
		int len = racine.length();
		if (len <= 1 || suffix.length() == 0)
			return racine + suffix;
		char dernier = last(racine);
		if (racine.charAt(len-2) == 'é' && !LatinScript.isVowel(dernier))
			return phonetiqueEacuteX(racine, suffix);
		switch (dernier) {
		case 'i':
			if (racine.endsWith("ei") && LatinScript.startsWithVowel(suffix))
				return replacerLast(racine, 'y') + suffix;
			if (LatinScript.startsWithVowel(suffix) && LatinScript.isVowel(racine.charAt(racine.length()-2)) && !eSon(suffix))
				racine = replacerLast(racine, 'y');
			return racine + suffix;
		case 'ï': // e.g.: haïr
			char x = suffix.charAt(0);
			if (x == 'i' || x == 'î')
				return racine + suffix.substring(1);
			break;
		case 'n':
			if (!racine.endsWith("nn") && !racine.endsWith("gn") && suffix.charAt(0) == 'e') {
				if (eSon(suffix)) {
					if (racine.endsWith("men"))
						return phonetiqueEX(racine, suffix);
					return racine + 'n' + suffix;
				}
				return racine + suffix;
			}
			break;
		case 'y':
			return (eSon(suffix) ? replacerLast(racine, 'i') : racine) + suffix;
		default:
			if (suffix.startsWith("u") && (racine.equals("m") || racine.equals("d")))
				return racine + 'û' + suffix.substring(1);
			if (racine.charAt(len-2) == 'e' && !LatinScript.isVowel(dernier))
				return phonetiqueEX(racine, suffix);
		}

		racine = phonetique(racine, suffix.charAt(0), dernierCSonDeS);
		if (suffix.length() == 1)
			return racine;
		return racine + suffix.substring(1);
	}

	static String phonetique(String racine, char suffix, boolean dernierCSonDeS) {
		int len = racine.length();
		if (len <= 1)
			return racine + suffix;
		char dernier = last(racine);
		if (racine.charAt(len-2) == 'é' && !LatinScript.isVowel(dernier))
			return phonetiqueEacuteX(racine, ""+suffix);

		char suffix_ = LatinScript.deAccent(suffix);
		switch (dernier) {
		case 'c':
			if (dernierCSonDeS) {
    			if (suffix_ == 'a' || suffix == 'o')
    				return replacerLast(racine, 'ç') + suffix;
			} else {
				if (LatinScript.isVowel(suffix))
					return chopRight(racine, 1) + "qu" + suffix;
			}
			break;
		case 'g':
			if (suffix_ == 'a' || suffix == 'o')
				return replacerLast(racine, "ge") + suffix;
			break;
		case 'i':
			if (racine.endsWith("ei") && LatinScript.isVowel(suffix))
				return replacerLast(racine, 'y') + suffix;
			break;
		case 'n':
			if (!racine.endsWith("nn") && !racine.endsWith("gn") && suffix == 'e')
				return racine + 'n' + suffix;
			break;
		case 'y': // oy, ay
			if (suffix == 'e')
				return replacerLast(racine, 'i') + suffix;
			break;
		default:
			if (suffix == 'u' && (racine.equals("m") || racine.equals("d")))
				return racine + 'û';
			if (racine.charAt(len-2) == 'e' && !LatinScript.isVowel(dernier))
				return phonetiqueEX(racine, String.valueOf(suffix));
		}

		return racine + suffix;
	}

	private static String phonetiqueEacuteX(String racine, String suffix) {
		if (eSon(suffix))
			return chopRight(racine, 2) + 'è' + last(racine) + suffix;
		return racine + suffix;
	}

	private static boolean etreStresseEX(String racine) {
		int len = racine.length();
		if (len <= 2)
			return false;
		char[] ca = racine.toCharArray();
		return ca[len-2] == 'e' && !LatinScript.isVowel(ca[len-1]) && !LatinScript.isVowel(ca[len-3]);
		// e.g. "gel", "pel", "enlev", "jet", "appel"
	}

	private static String phonetiqueEX(String racine, String suffix) {
		if (eSon(suffix) && etreStresseEX(racine)) {
			if (racine.endsWith("ppel") || racine.endsWith("jet"))
				return racine + last(racine) + suffix;
			return chopRight(racine, 2) + 'è' + last(racine) + suffix;
		}
		return racine + suffix;
	}
	
	private static boolean eSon(String suffix) {
		return suffix.charAt(0) == 'e' && !suffix.equals("ez");
	}

	static String[] appendToRoot(String racine, ImmutableStringList suffices) {
		String [] resulte = new String[suffices.size()];
		for (int i=0; i<suffices.size(); ++i) {
			String suffix = suffices.get(i);
			if (isEmpty(suffix)) {
				resulte[i] = racine;
			} else {
				if (racine.endsWith("tt") && !LatinScript.startsWithVowel(suffix))
					resulte[i] = replacerLast(racine, suffix);
				else
					resulte[i] = racine + suffix;
			}
		}
		return resulte;
	}

	static String[] appendToRoot(ImmutableStringList racines, ImmutableStringList suffices) {
		String [] resulte = new String[suffices.size()];
		for (int i=0; i<suffices.size(); ++i) {
			String racine = racines.get(i);
			String suffix = suffices.get(i);
			if (isEmpty(suffix)) {
				resulte[i] = racine;
			} else {
				if (racine.endsWith("tt") && !LatinScript.startsWithVowel(suffix))
					resulte[i] = replacerLast(racine, suffix);
				else
					resulte[i] = racine + suffix;
			}
		}
		return resulte;
	}

}
